package com.study.kt._03coroutines

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow

/**
 * <pre>
 *     author : slx
 *     time   : 2021/04/03
 *     desc   : Flow->Kotlin中的流是异步的（Java中的Stream）
 * </pre>
 */
/**
 * Flow是顺序执行的，Flow的收集操作，运行在调用了终止操作符的那个协程上，默认情况下，他是不会启动新的协程。
 * 每个emit的元素值都会由所有的中间操作进行处理，最后再由终止操作符处理，本质上，就是由上游进入到下游
 * 并不是所有元素同时进入中间操作，而是一个个进入中间操作
 *
 */
fun main() {
    // getList().forEach(::println)

    // getSeq().forEach(::println)

    /*runBlocking {
        useCoroutineList().forEach(::println)
    }*/

    // 测试Flow是否阻塞主线程,主线程方法和Flow结果交替运行
    runBlocking {
        launch {
            for (i in 0..3) {
                println("main:$i")
                delay(200)
            }
        }
        // Flow的迭代
        getFlowList().collect(::println)
    }
}

// 1.直接获取一个集合，阻塞主线程，而且是一起返回集合内容
private fun getList(): List<String> = listOf("fauks", "slx", "jay")

// 2.Sequence序列：如果每个元素的获取需要执行一定计算，该计算时阻塞行为，将计算后的结果返回给调用端
// 序列中的数据计算一个后返回给调用端而非一次性返回，计算过程是同步的会使用主线程，会造成阻塞
// 使用序列构建器 sequence{}构建序列
private fun getSeq(): Sequence<Int> = sequence {
    for (i in 100..105) {
        // 模拟耗时操作,每次获取一个元素之前都进行耗时操作，元素一个个返回
        Thread.sleep(1000)
        // 生成一个元素
        yield(i)
    }
}

// 3.为了不阻塞正在运行的主线程，改用协程,虽然不会阻塞主线程，但期望元素计算好一个返回一个
private suspend fun useCoroutineList(): List<String> {
    // 先休眠1s，元素统一返回
    delay(1000)
    return listOf("fauks", "slx")
}

// 4.使用Flow：不阻塞主线程，每个元素计算之后独自返回，计算过程是异步的
// Flow不需要使用suspend标识符，调用了collect方法后流才执行
private fun getFlowList(): Flow<Int> = flow {
    //
    withContext(Dispatchers.Default) {
        for (i in 100..105) {
            delay(100)
            // 如果此时使用Thread睡眠，那么先执行getFlowList完毕再执行主线程
            // 测试Thread是指让主线程睡眠
            // Thread.sleep(100)
            emit(i)
        }
    }
}